﻿using System;
using System.Collections.Generic;
using System.Linq;

using VSTalk.Engine.Core.Data;
using VSTalk.Engine.Core.Feed;
using VSTalk.Logger;

using agsXMPP;
using agsXMPP.Xml.Dom;
using agsXMPP.protocol.client;

using log4net;

using VSTalk.Tools;

namespace VSTalk.Engine.Core.History
{
    public class HistoryService : IHistoryService
    {
        private static readonly ILog _log = LoggerFactory.Create(typeof(HistoryService));

        private static IMessageFeed Feed
        {
            get { return AppServices.Get<IMessageFeed>(); }
        }

        private static IDatabaseManager DatabaseManager
        {
            get { return AppServices.Get<IDatabaseManager>(); }
        }

        private IHistoryDataProvider _dataProvider;
  
        public HistoryService(IHistoryDataProvider dataProvider)
        {
            _dataProvider = dataProvider;
            DatabaseManager.RegisterDA(_dataProvider);
        }

        public void Save()
        {
            _log.Info("Saving account history");
            var messages = Feed.GetMessages(message => true).Select(ToStoredItem).ToList();
            _dataProvider.SaveMessages(messages);
            _log.Info("Account history saved");
        }

        public IEnumerable<IMessage> Read(Guid clientId, Jid with)
        {
            var id = clientId.ToString("N");
            var withJid = with.Bare.ToLower();
            return _dataProvider.ReadMessages(id, withJid)
                .Select(ToHistoryItem);
        }

        public IEnumerable<IMessage> Read(Guid clientId, Jid with, DateTime @from)
        {
            var id = clientId.ToString("N");
            var withJid = with.Bare.ToLower();
            var fromTicks = from.Ticks;
            return _dataProvider.ReadMessages(id, withJid, fromTicks)
                .Select(ToHistoryItem);
        }

        public IEnumerable<IMessage> Read(Guid clientId, Jid with, DateTime @from, DateTime to)
        {
            var id = clientId.ToString("N");
            var withJid = with.Bare.ToLower();
            var fromTicks = from.Ticks;
            var toTicks = to.Ticks;
            return _dataProvider.ReadMessages(id, withJid, fromTicks, toTicks)
                .Select(ToHistoryItem);
        }

        public DateTime? LatestMessageDate(Guid clientId, Jid with)
        {
            var id = clientId.ToString("N");
            var withJid = with.Bare.ToLower();
            var ticks = _dataProvider.LatestMessageDate(id, withJid);
            if (ticks == -1)
            {
                return null;
            }
            return new DateTime(ticks);
        }

        private StoredMessage ToStoredItem(IMessage arg)
        {
            var bareFrom = arg.XmppMessage.From.With(jid => jid.Bare.ToLower());
            var bareTo = arg.XmppMessage.To.With(jid => jid.Bare.ToLower());
            var clientId = arg.ClientId.ToString("N");
            var ticks = arg.Date.Ticks;
            var messageXml = arg.XmppMessage.ToString();
            return new StoredMessage
            {
                ClientId = clientId,
                From = bareFrom,
                To = bareTo,
                Date = ticks,
                MessageXml = messageXml,
            };
        }

        private HistoryItem ToHistoryItem(StoredMessage arg)
        {
            return new HistoryItem
            {
                Date = new DateTime(arg.Date),
                XmppMessage = ToMessage(arg.MessageXml),
                ClientId = Guid.Parse(arg.ClientId)
            };
        }

        private Message ToMessage(string messageXml)
        {
            Document doc = new Document();
            doc.LoadXml(messageXml);
            return (Message)doc.RootElement;
        }
    }
}